/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Application;
import Application.Elements.*;
import java.io.FileNotFoundException;
import java.io.FileInputStream;
import java.util.*;
/**
 * Az aramkor leiro fajlok felparse-olasat vegzo osztaly
 * @author Stikmann
 */
public class NetworkFileParser {

    public Network net;
    public List<BTN> btns;
    public List<LED> leds;
    public List<Osc> oscs;
    public List<Wavegen> wavegens;
    private String lines[];

    /**
     * Parse-olast segito osztaly, igazabol egy struct, ami a fajlban detektelt
     * kompozit elem deklaraciokat tartja szamon
     */
    private class CompositeDeclaration {public String name; public int inputs; public int outputs; public int honnan; public int hova;}
    private Map<String,CompositeDeclaration> composites;


    /**
     * A fajl egy reszet felparse-olo segedfuggveny
     * @param hova A network osztaly ahova az elemek keruljenek
     * @param start A fajlmelyik soratol olvassa
     * @param end A fajl melyik sorabol olvassa
     * @param iscomposite Ha a hova parameter valojaban egy kompozit elem, ennek
     * igaznak kell lennie
     * @throws ParseSyntaxErrorException Ha barmifele szintaktikai hiba van
     */
    private void parseBlock(Network hova, int start, int end, boolean iscomposite) throws ParseSyntaxErrorException{
        Map<String,Element> elems=new HashMap();
        Map<String,CompositeElement> celems=new HashMap();
        CompositeDeclaration skipcomposite=null;
        
        

        for (int i=start;i<end;++i)
        {
            String cmd[]=lines[i].split("[ \t]+");
            if (cmd.length==0 ||cmd[0].length()==0)
                continue;
            // parameter nelkuli parancsok:
            if (skipcomposite!=null)
                if(cmd[0].equals("endcomposite"))
                {
                    skipcomposite.hova=i;
                    composites.put(skipcomposite.name,skipcomposite);
                    skipcomposite=null;
                    continue;
                }
                else
                    continue;
            else
                if(cmd[0].equals("endcomposite"))
                    throw new ParseSyntaxErrorException(i,"Varatlan ENDCOMPOSITE");


            //egyparameteres parancsok:
            if (cmd.length<2)
                throw new ParseSyntaxErrorException(i,"A(z) "+cmd[0]+" parancsnak legalabb 2 parameter kell, vagy ismeretlen.");
            if (cmd[0].equals("and")){
                AND elem=new AND();
                elem.name=cmd[1];
                elems.put(cmd[1], elem);
                hova.addGate(elem);
                continue;
            }
            if (cmd[0].equals("btn")){
                BTN elem;
                if (cmd.length>2)
                    if(cmd[2].equals("1"))
                        elem=new BTN(true);
                    else
                    if(cmd[2].equals("0"))
                        elem=new BTN(false);
                    else
                        throw new ParseSyntaxErrorException(i,"A BTN parancs parametere vagy 1, vagy 0.");
                else
                    elem=new BTN(false);
                elem.name=cmd[1];
                elems.put(cmd[1], elem);
                hova.addGate(elem);
                btns.add(elem);
                continue;
            }
            if (cmd[0].equals("led")){
                LED elem=new LED();
                elem.name=cmd[1];
                elems.put(cmd[1], elem);
                hova.addGate(elem);
                leds.add(elem);
                continue;
            }
            if (cmd[0].equals("not")){
                NOT elem=new NOT();
                elem.name=cmd[1];
                elems.put(cmd[1], elem);
                hova.addGate(elem);
                continue;
            }
            if (cmd[0].equals("or")){
                OR elem=new OR();
                elem.name=cmd[1];
                elems.put(cmd[1], elem);
                hova.addGate(elem);
                continue;
            }
            if (cmd[0].equals("osci")){
                Osc elem=new Osc();
                elem.name=cmd[1];
                elems.put(cmd[1], elem);
                hova.addGate(elem);
                oscs.add(elem);
                continue;
            }

            // A kompozit peldanyositas is egyparameteres
            if(composites.containsKey(cmd[0]))
            {
                CompositeDeclaration compdecl=composites.get(cmd[0]);
                CompositeElement comp=new CompositeElement(compdecl.inputs,compdecl.outputs);
                parseBlock(comp,compdecl.honnan,compdecl.hova,true);
                celems.put(cmd[1], comp);
                hova.addGate(comp);
                comp.typename=cmd[0];
                comp.name=cmd[1];
                continue;
            }

            //ketparameteres parancsok:
            if (cmd.length<3)
                throw new ParseSyntaxErrorException(i,"A(z) "+cmd[0]+" parancsnak legalabb 2 parameter kell, vagy ismeretlen.");

            if (cmd[0].equals("wavegen")){
                List<Boolean>sequence=new LinkedList<Boolean>();
                int len=cmd[2].length();
                for(int j=0;j<len;++j)
                    if (cmd[2].charAt(j)=='1')
                        sequence.add(true);
                    else
                    if (cmd[2].charAt(j)=='0')
                        sequence.add(false);
                    else
                        throw new ParseSyntaxErrorException(i,"A(z) wavegen parametere egy egyesekbol es nullakbol allo string kell legyen.");
                Wavegen elem=new Wavegen(sequence);
                elem.name=cmd[1];
                elems.put(cmd[1], elem);
                hova.addGate(elem);
                wavegens.add(elem);
                continue;
            }


            if (cmd[0].equals("wire")){
                Element elem1,elem2;
                if (cmd[1].contains("."))
                {
                    String tmp[]=cmd[1].split("\\.",2);
                    if (celems.get(tmp[0])!=null)
                        elem1=celems.get(tmp[0]).getOutput(Integer.parseInt(tmp[1]));
                    else
                        throw new ParseSyntaxErrorException(i,"A(z) "+tmp[0]+" elem nem letezo kompozit elem.");
                }else
                if(cmd[1].equals("gnd")){
                    GND gnd=new GND();
                    gnd.name="gnd";
                    hova.addGate(gnd);
                    elem1=gnd;
                }else
                if(cmd[1].equals("vcc")){
                    VCC vcc=new VCC();
                    vcc.name="vcc";
                    hova.addGate(vcc);
                    elem1=vcc;
                }else
                    elem1=elems.get(cmd[1]);


                if (cmd[2].contains("."))
                {
                    String tmp[]=cmd[2].split("\\.",2);
                    if (celems.get(tmp[0])!=null)
                        elem2=celems.get(tmp[0]).getInput(Integer.parseInt(tmp[1]));
                    else
                        throw new ParseSyntaxErrorException(i,"A(z) "+tmp[0]+" elem nem letezo kompozit elem.");
                }else
                if(cmd[2].equals("gnd")) {
                    GND gnd=new GND();
                    gnd.name="gnd";
                    hova.addGate(gnd);
                    elem2=gnd;
                }else
                if(cmd[2].equals("vcc")){
                    VCC vcc=new VCC();
                    vcc.name="vcc";
                    hova.addGate(vcc);
                    elem2=vcc;
                }else
                    elem2=elems.get(cmd[2]);

                if (elem1==null)
                    throw new ParseSyntaxErrorException(i,"A(z) "+cmd[1]+" nem letezik.");
                if (elem2==null)
                    throw new ParseSyntaxErrorException(i,"A(z) "+cmd[2]+" nem letezik.");

                hova.connectGate(elem1, elem2);
                continue;
            }

            if (cmd[0].equals("input")){
                if (iscomposite && hova instanceof CompositeElement){
                    CompositeElement comp=(CompositeElement)hova;
                    Element elem2;
                    if (cmd[2].contains("."))
                    {
                        String tmp[]=cmd[2].split("\\.",2);
                        if (celems.get(tmp[0])!=null)
                            elem2=celems.get(tmp[0]).getInput(Integer.parseInt(tmp[1]));
                        else
                            throw new ParseSyntaxErrorException(i,"A(z) "+tmp[0]+" elem nem letezo kompozit elem.");
                    }
                    else
                        elem2=elems.get(cmd[2]);

                    if (elem2==null)
                        throw new ParseSyntaxErrorException(i,"A(z) "+cmd[2]+" nem letezik.");

                    comp.connectInput(Integer.parseInt(cmd[1]), elem2);
                }
                else
                    throw new ParseSyntaxErrorException(i,"INPUT parancs használata kompozit elemen kivul.");
                continue;
            }

            if (cmd[0].equals("output")){
                if (iscomposite && hova instanceof CompositeElement){
                    CompositeElement comp=(CompositeElement)hova;
                    Element elem2;
                    if (cmd[2].contains("."))
                    {
                        String tmp[]=cmd[2].split("\\.",2);
                        if (celems.get(tmp[0])!=null)
                            elem2=celems.get(tmp[0]).getOutput(Integer.parseInt(tmp[1]));
                        else
                            throw new ParseSyntaxErrorException(i,"A(z) "+tmp[0]+" elem nem letezo kompozit elem.");
                    }else
                    if(cmd[2].equals("gnd")) {
                        GND gnd=new GND();
                        gnd.name="gnd";
                        hova.addGate(gnd);
                        elem2=gnd;
                    }else
                    if(cmd[2].equals("vcc")){
                        VCC vcc=new VCC();
                        vcc.name="vcc";
                        hova.addGate(vcc);
                        elem2=vcc;
                    }else
                        elem2=elems.get(cmd[2]);

                    if (elem2==null)
                        throw new ParseSyntaxErrorException(i,"A(z) "+cmd[2]+" nem letezik.");

                    comp.connectOutput(Integer.parseInt(cmd[1]), elem2);
                }
                else
                    throw new ParseSyntaxErrorException(i,"OUTPUT parancs használata kompozit elemen kivul.");
                continue;
            }

            //haromparameteres parancsok:
            if (cmd.length<4)
                throw new ParseSyntaxErrorException(i,"A(z) "+cmd[0]+" parancsnak legalabb 3 parameter kell, vagy ismeretlen.");

            if (cmd[0].equals("composite")){
                CompositeDeclaration compdecl=new CompositeDeclaration();
                compdecl.honnan=i+1;
                compdecl.name=cmd[1];
                compdecl.inputs=Integer.parseInt(cmd[2]);
                compdecl.outputs=Integer.parseInt(cmd[3]);
                skipcomposite=compdecl;
                continue;
            }

        }
    }
    /**
     * A megadott file-t felparseolja es visszaadja network objektumkent
     * @param filename A parseolando filenev
     */
    public void parse(String filename) throws ParseSyntaxErrorException, FileNotFoundException{
        Scanner fil=new Scanner(new FileInputStream (filename));
        List<String> linelist=new LinkedList();
        while(fil.hasNextLine()){
            String line=fil.nextLine()
                    .toLowerCase()
                    .trim()
                    .replaceAll("#.*$", "");//kommentek
            if (line.length()==0)
                continue;
            linelist.add(line);
        }
        lines=new String[linelist.size()];
        int i=0;
        for (String line:linelist)
            lines[i++]=line;
        net=new Network();
        composites=new HashMap();

        btns=new LinkedList();
        leds=new LinkedList();
        oscs=new LinkedList();
        wavegens=new LinkedList();
        parseBlock(net,0,lines.length,false);
        composites=null;
        fil.close();
    }
}
